
package com.scs.application.modules.order.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.BeanUtils;
import com.scs.application.core.utils.SerialOwnerUtils;
import com.scs.application.modules.order.entity.Delivery;
import com.scs.application.modules.order.entity.DeliveryItem;
import com.scs.application.modules.order.entity.DeliveryItemSn;
import com.scs.application.modules.order.mapper.DeliveryItemMapper;
import com.scs.application.modules.order.mapper.DeliveryItemSnMapper;
import com.scs.application.modules.order.mapper.DeliveryMapper;
import com.scs.application.modules.order.request.DeliveryItemSnQueryRequest;
import com.scs.application.modules.order.service.DeliveryItemSnService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * sn生成和查询 service 实现
 */
@Slf4j
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class DeliveryItemSnServiceImpl extends BaseServiceImpl<DeliveryItemSnMapper, DeliveryItemSn> implements DeliveryItemSnService {

    private final DeliveryItemMapper deliveryItemMapper;
    private final DeliveryMapper deliveryMapper;


    @Override
    public List<DeliveryItemSn> list(DeliveryItemSnQueryRequest request) {
        List<DeliveryItemSn> list = new ArrayList<>();
        list = this.list(Wrappers.<DeliveryItemSn>query()
                .eq(StringUtils.isNotEmpty(request.getDeliveryItemId()), "delivery_id", request.getDeliveryId())
                .eq(StringUtils.isNotEmpty(request.getDeliveryItemId()), "delivery_item_id", request.getDeliveryItemId())
                .orderByDesc("gmt_modified")
        );
        DeliveryItem deliveryItem = this.deliveryItemMapper.selectById(request.getDeliveryItemId());
        //如果sn为空或者sn数量不等于发货明细的数量
        if (list.isEmpty() || deliveryItem.getQty() != list.size()) {
            list = saveDeliveryItemSns(request.getDeliveryId(), request.getDeliveryItemId());
            list = list.stream().filter(o -> o.getDeliveryItemId().equals(request.getDeliveryItemId())).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public IPage<DeliveryItemSn> page(DeliveryItemSnQueryRequest request) {
        IPage page = this.page(request.getPage(), Wrappers.<DeliveryItemSn>query()
                .orderByDesc("gmt_modified")
        );
        return page;
    }

    @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED)
    @Override
    public List<DeliveryItemSn> saveDeliveryItemSns(String deliveryId, String deliveryItemId) {

        Delivery delivery = deliveryMapper.selectById(deliveryId);
        if (delivery == null) {
            return Collections.emptyList();
        }

        List<DeliveryItemSn> deliveryItemSnList = Lists.newArrayList();
        List<DeliveryItemSn> allReturnSnList = this.list(Wrappers.<DeliveryItemSn>query()
                .eq("delivery_id", deliveryId)
                .orderByDesc("gmt_modified"));
//        查询发货单明细
        List<DeliveryItem> deliveryItems;
        if (deliveryItemId == null) {
            deliveryItems = deliveryItemMapper.selectList(Wrappers.<DeliveryItem>query()
                    .eq("delivery_id", deliveryId)
                    .orderByDesc("gmt_modified"));


        } else {
            deliveryItems = deliveryItemMapper.selectList(Wrappers.<DeliveryItem>query()
                    .eq("delivery_id", deliveryId)
                    .eq("id", deliveryItemId)
                    .orderByDesc("gmt_modified"));
        }
        for (DeliveryItem deliveryItem : deliveryItems) {
            Double qty = deliveryItem.getQty();
            int qtyItem = (int) Math.round(qty);
            // 查询发货单明细生成的SN
            List<DeliveryItemSn> returnSnList = allReturnSnList != null && allReturnSnList.size() > 0 ?
                    allReturnSnList.stream().filter(sn -> deliveryItem.getId().equals(sn.getDeliveryItemId())).collect(Collectors.toList()) : Lists.newArrayList();
            if (!returnSnList.isEmpty() && qtyItem == returnSnList.size()) {
                BeanUtils.copyProperties(returnSnList, deliveryItemSnList, DeliveryItemSn.class);
                continue;
            } else {
                //删除SN
                this.baseMapper.delete(Wrappers.<DeliveryItemSn>query()
                        .eq("delivery_item_id", deliveryItem.getId()));
            }

            /** 批量生成sn编码 */
            List<String> codes = SerialUtils.batchGenerateCode(
                    SerialRuleConsts.ORDER_DELIVERY_SN, SerialOwnerUtils.getHospitalOwner(delivery.getHospitalId()), (int) qtyItem);
            int codeIndex = 0;
            for (long i = 0; i < qtyItem; i++) {
                DeliveryItemSn deliveryItemSn = new DeliveryItemSn();
                deliveryItemSn.setSn(codes.get(codeIndex++))
                        .setDeliveryId(deliveryItem.getDeliveryId())
                        .setDeliveryItemId(deliveryItem.getId())
                        .setUdi(deliveryItem.getUdi())
                        .setId(null);
                deliveryItemSnList.add(deliveryItemSn);
            }

        }
        boolean insertSNBool = saveOrUpdateBatch(deliveryItemSnList);
        if (!insertSNBool) {
            throw new BusinessException("生成SN失败,请重试");
        }

        Map<String, DeliveryItem> deliveryItemMap = deliveryItems.stream().collect(Collectors.toMap(DeliveryItem::getId, item -> item, (left, right) -> left));
        if (deliveryItemMap != null && deliveryItemSnList != null) {
            for (DeliveryItemSn item : deliveryItemSnList) {
                if (deliveryItemMap.containsKey(item.getDeliveryItemId())) {
                    item.setMatrUdi(deliveryItemMap.get(item.getDeliveryItemId()).getUdi());
                }
            }
        }

        return deliveryItemSnList;
    }

}
